EF entiteit en model
Een entiteit is een klasse die toegewezen is aan een Entity Framework context met een eigen identiteit, of een eigenschap die op een unieke wijze instanties ervan identificeert. In DDD (domain driven design) jargon, spreekt men van een aggregate root als het de bedoeling is om de entiteit direct te bevragen, denk aan een Person
of een Country
. Een entiteit kan ook samen met een aggregate root worden geladen en niet op zichzelf bestaan zoals bijvoorbeeld OrderItem. Een entiteit wordt opgeslagen in zijn eigen tabel en kan één of meerdere validatie-methoden hebben.
Model
Zo'n entiteit wordt in het MVC jargon een model genoemd.
Een domein model waarin de entiteiten alleen eigenschappen (gegevens) en geen methoden (gedrag) bevatten, wordt ook wel een anemisch domein model genoemd. Je kunt een goede beschrijving voor deze anti-patroon op Martin Fowler's website.
We gaan in deze lessen dan ook met DDD of het Domain Driven Design (DDD - Domain-Driven Design) toepassen.
De entiteitsklase kan verschillende soorten eigenschappen bevatten.
Scalaire eigenschap
Scalaire eigenchappan zijn eenvoudig waarden, zoals strings, datums en getallen. Daarin worden de data van de entiteit opgeslagen,
SQL Data Types | .Net | Omschrijving |
bigint | Int54 | Integer data van -2^63 (-9223372036854775808) tot 2^63-1 (9223372036854775807) |
int | Int32 | Integer data van -2^31 (-2.147.483.648) tot 2^31-1 (2.147.483.647) |
smallint | Int16 | Integer data van -2^15 (-32,768) tot 2^15-1 (32.767) |
tinyint | Byte | Integer data van 0 tot 255 |
bit | Boolean | Integer data van 1 of 0 (Boolean bijv. ja/nee) |
decimal | Decimal | Numerieke data types als niet opgegeven dan van -10^38+1 tot 10^38-1 (p) Precision : De maximale totale lengte van decimale digits die opgeslagen kunnen worden. (s) Scale : Het maximale aantal nummers die rechts van de komma opgeslagen kunnen worden. |
numeric | Idem decimal | |
money | Decimal | Valuta data van -2^63 (-9223372036854775808) tot 2^63-1 (9223372036854775807) |
smallmoney | Decimal | Valute data van -2.147.483.648) tot 2^31-1 (2.147.483.647) |
float | Double | Floating precisie nummer data van - 1.79E + 308 tot -2.23E - 308, 0 en 2.23E -308 tot 1.79E + 308 |
real | Single | idem float |
datetime | DateTime | Datum en tijd van 1 januari 1753 tot 31 december 9999 met een precisie van 3.33 milliseconde |
smalldatetime | DateTime | Datum en tijd van 1 januari 1900 tot 6 juni 2079 met een precisie van 1 seconde |
char | Char | Vaste lengte character data met een lengte van 8000 character |
varchar | string | Variabele lengte data met een maximum lengte van 8000 characters |
nchar | string | Vaste lengte unicode data met een lengte van 4000 Characters |
nvarchar | string | Variabele lengte unicode data met een maximum lengte van 4000 Characters |
binary | Byte[] | Vaste lengte binary data met een vaste lengte van 8000 bytes |
varbinary | Byte[] | Variabele lengte binary data met een vaste lengte van 8000 bytes |
timestamp | DateTime | een database-wide unieke nummer dat iedere keer geupdate wordt als de rij gemuteerd wordt |
uniqueidentifier | Guid | een globally unique identifier |
Voor de types Byte, Char en String kan je een maximale lengte opgegeven. Een waarde van -1 betekent de maximum waarde. Alle scalaire types kunnen nullable worden gemaakt, wat betekent dat ze kan geen ingestelde waarde kunnen hebben. In de databank wordt dit weergegeven door een NULL kolom. Scalaire eigenschappen moeten zowel een getter en een setter hebben, maar een setter kan een beperkter bereik hebben dan de getter: internal, protected internal of protected.
Enkele voorbeelden
public int OrderID { get; set; } public int CustomerID { get; set; } public DateTime OrderDate { get; set; } public int CustomerID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; }
Identiteitseigenschap (identity property) of entiteitssleutel
Één of meer van de scalaire eigenschappen van je entiteit moet de primaire sleutel van de onderliggende tabel voorstellen. Die sleutel kan enkelvoudig of samengestelde zijn.
Een primaire-sleutel-eigenschap moet één van de basistypen zijn uit de lijst hierboven. Dus geen arrays en opsommingen, en ook geen complexe eigenschappen of typen gebaseerd op een andere entiteit.
In Entity Frameworkmoet elke entiteit een sleutelwaarde hebben. Er bestaat een afspraak (conventie, Conventie boven configuratie) om te zoeken naar een eigenschap met de naam Id
of een eigenschap die de klassenaam en Id
, zoals "PersonId", combineert. De eigenschap wordt toegewezen aan een primary key kolom in de database. In EF spreekt men van een identiteitseigenschap of entiteitssleutel en in SQL van een primary key.
public class Country { public int Id { get; set; } public string Name{ get; set; } public string Code{ get; set;} }
Onze klasse voor Person, User, Country, Event, enz zullen deze afspraak volgen. Maar wat als ze dat niet deden? Wat als Person in plaats daarvan de naam PrimaryTrackingKey zou gebruiken of zelfs Plopperdeplop? Als EF geen eigenschap vindt die voldoet aan deze conventie, krijg je een foutmelding want een identiteitseigenschap is een vereiste van EF. Maar je kan wel de de key-annotatie gebruiken om op te geven welke eigenschap als de EntityKey moet worden gebruikt.
public class Country { [Key] public int Id { get; set; } public string Name{ get; set; } public string Code{ get; set;} }
De volledige code voor de Role
entiteit met data annotaties (EF Core - Business regels toevoegen met attributen - Data Annotations):
/* Class: Role * modernways.be * created by an orm apart * Entreprise de modes et de manières modernes * Model for docent1 app * FileName: Models/Role.cs * Created on Sunday 3rd of December 2017 12:10:59 PM */ using System; using System.ComponentModel.DataAnnotations; namespace LerenWerkenMetEF.Models { public class Role { // fields protected String name; protected Int32 id; // Getters and setters // [Index(IsUnique = true)] wordt niet ondersteund in EF Core? [Required(ErrorMessage = "Het veld Naam is verplicht!")] [MaxLength(50, ErrorMessage = "Name bestaat uit maximum 50 karakters.")] public String Name { get { return this.name; } set { this.name = value; } } [Required(ErrorMessage = "Het veld Id is verplicht!")]] public Int32 Id { get { return this.id; } set { this.id = value; } } } }
Referentieeigenschap (reference property)
Een verwijzing van een entiteit naar de andere definieert een bidirectionele relatie. Er zijn twee types verwantschapsrelaties:
- veel-op-één (many-to-one): meerdere instanties van een entiteit kunnen aan dezelfde instantie van een ander type (zoals OrderItems die eigendom zijn van Order) gekoppeld worden;
- één-op-één (one-to-one): een instantie van een entiteit wordt gekoppeld aan een andere instantie van een entiteit; deze andere instantie wordt alleen geassocieerd met de eerste (bijvoorbeeld een OrderItem en het Product);
In EFCF worden meerdere instanties, die gekoppeld zijn aan een instantie van een ander type, voorgesteld door collecties. En een associatie wordt vertegenwoordigd door een eigenschap van het type van de andere entiteit.
public class Customer { // one end point of a many to one relationship // a customer has one of many orders public virtual ICollectionOrders { get; set; } }
public class OrderItem { // one endpoint of one to one relationship // one OrderItem belongs to one order public virtual Order Order { get; set; } // one OrderItem has one Product public virtual Product Product { get; set; } }
Door alleen te kijken naar één eindpunt, kunnen we niet direct zeggen wat het type is (één-op-één of veel-op-een), we moeten kijken naar beide eindpunten.
In Entity Framework kan je collecties alleen declareren als ICollection
(of een afgeleide klasse of interface) eigenschappen. In de entiteit, worden de collecties eigenschappen altijd in de constructor geïnitialiseerd.
Complexe eigenschap (complex property)
Dit onderdeel is nog niet klaar.